package com.dferreira.repository.data_utils;

import android.content.Context;

import com.dferreira.repository.RepositoryDatabaseHelper;
import com.dferreira.repository.data_models.FileEntry;
import com.dferreira.repository.data_models.PackageMetadata;
import com.j256.ormlite.dao.RuntimeExceptionDao;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class FileEntryZIPExtractor {

    private String packagesPath;
    private ZipInputStream zis;
    private ZipEntry zipEntry;
    private RepositoryDatabaseHelper repositoryDbHelper;

    public FileEntryZIPExtractor(Context context) {
        super();
        this.repositoryDbHelper = new RepositoryDatabaseHelper(context);
    }

    /**
     * if the directory does not exist, create a folder able to retain the
     * package information
     *
     * @return null -> everything worked well null null -> An error describing
     * the error
     */
    public String setPackageFolder(String path) {
        File packagesDirectory;
        packagesDirectory = new File(path);
        if (packagesDirectory.exists() || packagesDirectory.mkdirs()) {
            this.packagesPath = path;
            return null;
        } else {
            return "Could not create the directory to unzip files";
        }
    }

    /**
     * Starts open the ZipInputStream
     */
    public void beginInstallingPackage(InputStream fis) {
        zis = new ZipInputStream(fis);
    }

    /**
     * Gets the next entry from the zip file
     *
     * @return false -> could not read the next entry
     * true -> was possible read the next entry
     */
    public boolean fetchNextEntry() {
        try {
            zipEntry = zis.getNextEntry();
            if (zipEntry == null) {
                return false;
            }
        } catch (IOException ex) {
            ex.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * Decompresses the current entry from the zip file and sets saves his information in
     * the table
     *
     * @param pkg package which the entry belongs
     * @return size from the entry that was installed
     */
    public long installAnEntry(PackageMetadata pkg) {
        byte[] buffer = new byte[1024];
        File file;
        FileOutputStream fos;
        int nBytes;
        long fileSize;

        try {
            System.out.println("entry name:" + zipEntry.getName());
            file = new File(packagesPath + File.separator + zipEntry.getName());
            if (zipEntry.isDirectory()) {
                if (file.exists() || file.mkdir()) {
                    return 0;
                } else {
                    return -1;
                }
            } else {
                fos = new FileOutputStream(file);
                fileSize = 0;
                while ((nBytes = zis.read(buffer)) != -1) {
                    fos.write(buffer, 0, nBytes);
                    fileSize += nBytes;
                }
                fos.close();
            }
            createFileEntry(pkg, packagesPath + File.separator + zipEntry.getName(), fileSize);


            zis.closeEntry();
        } catch (IOException ex) {
            return -1;
        }
        return fileSize;
    }

    /**
     * @param packageMetadata
     * @return
     */
    private int createFileEntry(PackageMetadata packageMetadata, String path, Long size) {
        FileEntry fileEntry;

        fileEntry = new FileEntry();
        fileEntry.setPackageMetadata(packageMetadata);
        fileEntry.setPath(path);
        fileEntry.setSize(size);

        RuntimeExceptionDao<FileEntry, Integer> dao = repositoryDbHelper.getFileEntryDao();
        return dao.create(fileEntry);
    }
}
